package com.ra.landlord;

import java.io.OutputStream;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.da.landlord.DaRoom;
import com.espirit.eap.manager.SystemLogService;
import com.espirit.eap.manager.TaskSchedulerService;
import com.espirit.eap.sa.LoginUserService;
import com.espirit.eap.util.Functions;
import com.espirit.weixin.core.WeixinUtil;
import com.googlecode.cswish.annotation.Rest;
import com.googlecode.cswish.exception.ApplicationException;
import com.googlecode.cswish.model.KeyValue;
import com.googlecode.cswish.model.PageInfo;
import com.googlecode.cswish.model.Reference;
import com.googlecode.cswish.oosearch.Condition;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.security.SafeManager;
import com.googlecode.cswish.security.auth.UserInfo;
import com.googlecode.cswish.struts.Routing;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.util.WebsiteUtil;
import com.opensymphony.xwork2.Result;
import com.ra.external.WeixinUserService;
import com.ra.order.OrderUtil;
import com.ra.order.rental.RentalOrder;
import com.ra.pay.alipay.AlipayService;
import com.ra.pay.alipay.AlipayUtil;
import com.ra.pay.weixin.WeixinPay_bakService;
import com.ra.util.SmsLog;
import com.ra.util.SmsService;

@Service
public class TransferRentalRecordService {
	
	private static final Log logger = LogFactory.getLog(AlipayUtil.class);

	@Resource
	private GenericService genericService;
	
	@Resource
	private AlipayService alipayService;
	
	@Resource
	private LoginUserService loginUserService;
	
	@Resource
	private ObjectFactory objectFactory;
	
	@Resource
	private WeixinUserService weixinUserService;
	
	@PersistenceContext(unitName = "espirit")
	protected EntityManager em;
	
	@Resource
	private SmsService smsService;
	
	@Resource
	private FeeAdditionService feeAdditionService;
	
	@Resource
	private LandlordUserService landlordUserService;
	
	@Resource
	private LandlordPurchaseInfoService landlordPurchaseService;
	
	@Resource
	private FeeService feeService;
	
	@Resource
	private Functions functions;
	
	@Resource 
	private WeixinPay_bakService weixinPayService;
	
	@Resource
	private RoomService roomService;
	
	@Resource
	private FeeRecordService feeRecordService;
	
	@Resource
	private TenantUserService tenantUserService;
	
	@Resource
	private WeixinUtil weixinUtil;
	
	@Resource
	private TaskSchedulerService taskSchedulerService;
	
	@Resource
	private SystemLogService systemLogService;
	
	@Resource
	private SafeManager safeManager;
	
	private List<KeyValue> bankCardEnumList;
	
	private TransferRentalRecordService transferRentalRecordService;
	
	private TransferRentalRecordService getThis() {
		if (transferRentalRecordService == null) {
			transferRentalRecordService = ObjectFactory.getInstance().getBean(TransferRentalRecordService.class, false);
		}
		return transferRentalRecordService;
	}

	/**
	 * 定时器生成转账记录
	 * @return
	 */
	public void addTodayTranRecords() {
		// 查询数据库中待转账记录
		TransferRentalRecord queryExised = new TransferRentalRecord();
		queryExised.setTransferState(TransferRentalRecord.TRANSFER_STATE_DOING);
		List<TransferRentalRecord> exiseds = genericService.searchAll(queryExised).getData();
		List<RentalOrder> noContains = new ArrayList<RentalOrder>();
		for(TransferRentalRecord exised : exiseds) {
			List<RentalOrder> temps = exised.getRentalOrders();
			noContains.addAll(temps);
		}
		
		// 查询已付款订单记录
		RentalOrder queryModel = new RentalOrder();
		queryModel.setOrderState(RentalOrder.ORDER_STATE_PAYMENTED);
		List<RentalOrder> rentalOrders = genericService.searchAll(queryModel).getData();
		List<RentalOrder> removeOrders = new ArrayList<RentalOrder>();
		for(RentalOrder order : rentalOrders) {
			for(RentalOrder noContain : noContains) {
				if(order.getId() == noContain.getId()) {
					removeOrders.add(order);
					break;
				}
			}
		}
		rentalOrders.removeAll(removeOrders);
		Map<Integer, List<RentalOrder>> map = new HashMap<Integer, List<RentalOrder>>();
		if(CollectionUtils.isNotEmpty(rentalOrders)) {
			for(RentalOrder rentalOrder : rentalOrders) {
				Integer landlordUserId = null;
				if(rentalOrder.getRoom() != null && rentalOrder.getRoom().getLandlordUser() != null) {
					landlordUserId = rentalOrder.getRoom().getLandlordUser().getId();
				} else if(rentalOrder.getDaRoom() != null &&  rentalOrder.getDaRoom().getLandlordUser() != null) { // 分散式房源
					landlordUserId = rentalOrder.getDaRoom().getLandlordUser().getId();
				} else {
					continue;
				}
				if(map.containsKey(landlordUserId)) {
					map.get(landlordUserId).add(rentalOrder);
				} else {
					List<RentalOrder> temp = new ArrayList<RentalOrder>();
					temp.add(rentalOrder);
					map.put(landlordUserId, temp);
				}
			}
		}
		
		Iterator<Map.Entry<Integer, List<RentalOrder>>> it = map.entrySet().iterator();
		TransferRentalRecord transferRentalRecord = null;
		List<TransferRentalRecord> transfers = new ArrayList<TransferRentalRecord>();
		while (it.hasNext()) {
			   Map.Entry<Integer, List<RentalOrder>> entry = it.next();
			   Integer landlordUserId = entry.getKey();
			   LandlordUser queryUser = new LandlordUser();
			   queryUser.setId(landlordUserId);
			   LandlordUser landlordUser = genericService.load(queryUser);
			   List<RentalOrder> landlordOrders = entry.getValue();
			   
			   transferRentalRecord = new TransferRentalRecord();
			   if(landlordUser != null) {
				   transferRentalRecord.setLandlordUser(landlordUser);
			   }
			   transferRentalRecord.setOrderNum(landlordOrders.size());
			   Date date = new Date();
			   Timestamp createTime = new Timestamp(date.getTime());
			   transferRentalRecord.setCreateTime(createTime);
			   transferRentalRecord.setRentalOrders(landlordOrders);
			   
			   // 付款当天日期20150808
			   Calendar now = Calendar.getInstance();
			   int year = now.get(Calendar.YEAR);
			   int month = now.get(Calendar.MONTH) + 1;
			   int day = now.get(Calendar.DATE);
			   transferRentalRecord.setTransferDate( "" + year + month + day);
			   transferRentalRecord.setTransferFee(this.getTotalFee(landlordOrders));
			   // 转账流水号
			   transferRentalRecord.setTransferNo("T" + OrderUtil.getOrderNum());
			   transferRentalRecord.setTransferState(TransferRentalRecord.TRANSFER_STATE_DOING);
			   
			   transfers.add(transferRentalRecord);
		}
		
		for (TransferRentalRecord record : transfers) {
			try {
				for(RentalOrder mergeOrder : record.getRentalOrders()) {
					mergeOrder.setTransferRentalRecord(record);
				}
				genericService.merge(record);
			} catch (Exception ex) {
				logger.error("Failed to generate transfer rental record", ex);
				
				HttpServletRequest request = ServletActionContext.getRequest();
				UserInfo userInfo = safeManager.getLoginUser(request);
            	String userId = userInfo == null ? "anony" : userInfo.getLoginId();
            	String ip = WebsiteUtil.getRemoteIp(request);
            	String uri = Routing.getUri(request);
				systemLogService.log(userId, ip, uri, record.getTransferNo(), ex);
			}
		}
		
		taskSchedulerService.updateTaskSchedulerRunTime(this.getClass(), "addTodayTranRecords");
	}
	
	private BigDecimal getTotalFee(List<RentalOrder> rentalOrders) {
		BigDecimal totalFee = new BigDecimal("0.00");
		for(RentalOrder rentalOrder : rentalOrders) {
			totalFee = totalFee.add(rentalOrder.getTotalFee());
		}
		return totalFee;
	}
	
	/**
	 * 根据当前登录房东查询所有转账记录
	 * @return
	 */
	public List<TransferRentalRecord> searchTransfersByLandlordUserId(TransferRentalRecord model) {
		// 获取当前登录用户的房东
		LandlordUser landlordUser = landlordUserService.getLandlordUser();
		TransferRentalRecord queryModel = new TransferRentalRecord();
		queryModel.setLandlordUser(landlordUser);
		if(StringUtils.isNotBlank(model.getTransferDate())) {
			queryModel.setTransferDate(model.getTransferDate());
		}
		
		Condition condition = new Condition();
		condition.setCompareFlag(Condition.COMPARE_AUTO_LIKEFIRST);
		condition.setSort("createTime");
		condition.setDir("DESC");
		condition.setEnableCache(true);
		List<TransferRentalRecord> results = genericService.searchByModel(queryModel, condition).getData();
		
		// TODO 避免APP重新发版本临时解决方案
		if(CollectionUtils.isNotEmpty(results)) {
			for(TransferRentalRecord transferRentalRecord : results) {
				List<RentalOrder> rentalOrders =  transferRentalRecord.getRentalOrders();
				if(CollectionUtils.isNotEmpty(rentalOrders)) {
					for(RentalOrder rentalOrder : rentalOrders) {
						Room room = rentalOrder.getRoom();
						DaRoom daRoom = rentalOrder.getDaRoom();
						if(room == null) {
							room = new Room();
							Building building = new Building();
							building.setId(daRoom.getSuite().getId());
							building.setName(daRoom.getSuite().getName());
							room.setName(daRoom.getName());
							room.setId(daRoom.getId());
							room.setBuilding(building);
						} else if(room.getName() == null) {
							room.setName(daRoom.getName());
							room.setId(daRoom.getId());
							Building building = room.getBuilding();
							building.setId(daRoom.getSuite().getId());
							building.setName(daRoom.getSuite().getName());
							room.setBuilding(building);
						}
						rentalOrder.setRoom(room);
					}
				}
			}
		}
		
		return results;
	}

	/**
	 * CRM查询所有转账记录
	 * @return
	 */
	public PageInfo<TransferRentalRecord> searchTransfersByCRM(TransferRentalRecord model, int start, int limit,
	    		String sort, String dir, boolean oldSearch, boolean fromMenu, Reference<QLInfo> qlInfoRef) {
		if (fromMenu) {
			model.setTransferState(TransferRentalRecord.TRANSFER_STATE_DOING);
		}
		return genericService.search(model, start, limit, sort, dir, oldSearch, qlInfoRef, null, true, true);
	}
	
	/**
	 * 获取账单详情
	 * 
	 * @param model
	 * @return
	 */
	@Rest(type = "searchTransfersByCRM")
	public List<RentalOrder> getTransfersDetail(TransferRentalRecord model) {
		TransferRentalRecord dbTransferRentalRecord = genericService.load(model);
		return dbTransferRentalRecord.getRentalOrders();
	}
	
	public Result exportTransfersByCRM(List<TransferRentalRecord> results) {
		try {
			String excelFilName = "房东转帐记录" + new SimpleDateFormat("yyyyMMdd").format(Calendar.getInstance().getTime());
			HttpServletResponse response = ServletActionContext.getResponse();
	        String fileName = new String(excelFilName.getBytes("UTF-8"), "ISO8859_1")  + ".csv";
	        response.reset();
	        String contentType = "application/vnd.ms-excel";
	        response.setContentType(contentType);
	        response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
			
			OutputStream outputStream = response.getOutputStream();
			
			String title = "帐号,户名,金额,开户行,开户地,注释\r\n";
			String contentTpl = "%s,%s,%s,%s,%s,%s\r\n";
			
			StringBuilder csvContent = new StringBuilder();
			csvContent.append(title);
			for (TransferRentalRecord model : results) {
				if (model == null || model.getId() == null) {
					continue;
				}
				
				TransferRentalRecord dbTransferRentalRecord = genericService.load(model);
				String comment = dbTransferRentalRecord.getTransferDate() + "租金:" + dbTransferRentalRecord.getTransferFee() + "";
				
				List<BankCard> cards = dbTransferRentalRecord.getLandlordUser().getBankCards();

				if (cards != null && cards.size() > 0) {
					BankCard bankCard = cards.get(0);
					if (bankCard != null) {
						String content = String.format(contentTpl, notNUll(bankCard.getCardNumber()), notNUll(bankCard.getName())
								, notNUll(dbTransferRentalRecord.getTransferFee()), notNUll(bankCard.getIssuing())
								, notNUll(bankCard.getAddress()), notNUll(comment));
						csvContent.append(content);
					}
				}
			}
			
			byte commonCsvHead[] = { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };
			IOUtils.write(commonCsvHead, outputStream);
			IOUtils.write(csvContent.toString(), outputStream, "utf-8");
		} catch (Exception ex) {
			logger.error("Fail to export excel", ex);
		}
		return null;
	}
	
	private Object notNUll(Object val) {
		return val == null ? "" : val;
	}
	
	/**
	 * CRM确定转账成功
	 * @param results
	 * @return true
	 */
	public boolean onSureTransfersByCRM(List<TransferRentalRecord> results) {
		if (CollectionUtils.isNotEmpty(results)) {
			for (TransferRentalRecord transfer : results) {
				if (transfer == null || transfer.getId() == null) {
					continue;
				}
				
				getThis().onsureTransfer(transfer);
			}
		}
		return true;
	}
	
	private List<KeyValue> getBankCardEnumList() {
		if (bankCardEnumList == null) {
			bankCardEnumList = functions.enumList(BankCard.class.getName(), "issuing");
		}
		return bankCardEnumList;
	}
	
	@Transactional
	public void onsureTransfer(TransferRentalRecord transfer) {
		TransferRentalRecord existed = genericService.load(transfer);
		boolean transfered = existed.getTransferState() != null && existed.getTransferState() == TransferRentalRecord.TRANSFER_STATE_SUCCESS;
		if (transfered) {
			return ;
		}
		
		List<RentalOrder> rentalOrders = existed.getRentalOrders();
		if (CollectionUtils.isNotEmpty(rentalOrders)) {
			for (RentalOrder updateOrder : rentalOrders) {
				updateOrder.setOrderState(RentalOrder.ORDER_STATE_SUCCESS);
				genericService.update(updateOrder);
			}
		}
		
		existed.setTransferState(TransferRentalRecord.TRANSFER_STATE_SUCCESS);
		genericService.merge(existed);
		
		LandlordUser landlordUser = existed.getLandlordUser();
		String mobile = landlordUser.getPhone();
		String issuing = landlordUser.getBankCards().get(0).getIssuing();
		String issuingDesc = issuing;
		for (KeyValue kv : getBankCardEnumList()) {
			if (issuing.equals(kv.getKey())) {
				issuingDesc = kv.getValue();
				break;
			}
		}
		
		String content;
		BigDecimal milliActivityFee = new BigDecimal(0);
		int realOrderSize = rentalOrders.size();
		boolean attendMilliActivity = landlordUser.getAttendMilliActivity() != null && landlordUser.getAttendMilliActivity();
		if (attendMilliActivity) {
			if (CollectionUtils.isNotEmpty(rentalOrders)) {
				for (RentalOrder updateOrder : rentalOrders) {
					if (updateOrder.getOrderName().endsWith("交租补贴")) {
						realOrderSize--;
						milliActivityFee = milliActivityFee.add(updateOrder.getTotalFee());
					}
				}
			}
		}
		if (milliActivityFee.floatValue() > 0) {
			content = String.format("%s您好，感谢您参与好好租“百万补贴房东活动“，已有%s笔租金共计%s元转到您%s账户（其中活动补贴%s元），请注意查收！", 
					landlordUser.getDisplayName(), realOrderSize,  existed.getTransferFee(), issuingDesc, milliActivityFee);
		} else {
			content = String.format("%s您好，已有%s笔租金共计%s元转到您%s账户，请注意查收！",
				landlordUser.getDisplayName(), realOrderSize,  existed.getTransferFee(), issuingDesc);
		}
		smsService.sendMessage(mobile, SmsLog.TYPE_SEND_TRANSFER, content, true, null, SmsService.CHANEL_NORMAL, null);
	}
	
	/**
	 * 特殊情况合并转账记录，将相同房东的转账记录合并成一条
	 * 合并之前判断是否为同一个房东
	 * 在Model中增加一个状态，标识被合并的转账记录
	 * @param transferIds
	 * @return 合并后的转账记录
	 */
	public TransferRentalRecord mergeTransferRecords(List<Integer> transferIds) {
		TransferRentalRecord mergeTransfer = new TransferRentalRecord();
		for (Integer transferId : transferIds) {
			TransferRentalRecord tempOne = genericService.load(
					TransferRentalRecord.class, transferId);
			for (Integer transferOtherId : transferIds) {
				TransferRentalRecord tempTwo = genericService.load(
						TransferRentalRecord.class, transferOtherId);
				if (tempOne.getLandlordUser().getId() != tempTwo
						.getLandlordUser().getId()) {
					throw new ApplicationException("当前选择转账单所属房东不一致，请重新选择！");
				}
			}
		}

		List<RentalOrder> rentalOrders = new ArrayList<RentalOrder>();
		LandlordUser landlordUser = null;
		for (Integer transferId : transferIds) {
			TransferRentalRecord temp = genericService.load(
					TransferRentalRecord.class, transferId);
			landlordUser = temp.getLandlordUser();
			List<RentalOrder> tempOrders = temp.getRentalOrders();
			if(CollectionUtils.isNotEmpty(tempOrders)) {
				rentalOrders.addAll(tempOrders);
			}
			temp.setTransferState(TransferRentalRecord.TRANSFER_STATE_MERGE);
			genericService.update(temp);
		}

		// 组装合并后的转账记录
		if (landlordUser != null) {
			mergeTransfer.setLandlordUser(landlordUser);
		}
		mergeTransfer.setOrderNum(rentalOrders.size());
		Date date = new Date();
		Timestamp createTime = new Timestamp(date.getTime());
		mergeTransfer.setCreateTime(createTime);
		mergeTransfer.setRentalOrders(rentalOrders);

		// 付款当天日期20150808
		Calendar now = Calendar.getInstance();
		int year = now.get(Calendar.YEAR);
		int month = now.get(Calendar.MONTH) + 1;
		int day = now.get(Calendar.DATE);
		mergeTransfer.setTransferDate("" + year + month + day);
		mergeTransfer.setTransferFee(this.getTotalFee(rentalOrders));
		// 转账流水号
		mergeTransfer.setTransferNo("T" + OrderUtil.getOrderNum());
		mergeTransfer.setTransferState(TransferRentalRecord.TRANSFER_STATE_DOING);
		return genericService.add(mergeTransfer);
	}
}
